package com.ipan.poi.excel.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.poi.utils.PoiClassLoaderHelper;
import com.ipan.poi.utils.PoiStringHelper;

/**
 * 配置文件抽象类
 * 
 * @author iPan
 * @version 2013-9-14
 */
public abstract class XlsConfiguration {

	protected XlsRoot root = null;
	protected static Logger logger = LoggerFactory.getLogger(XlsConfiguration.class);
	
	public XlsConfiguration(XlsRoot root) {
		this.root = root;
	}
	
	public XlsConfiguration addConfig(String classPath) {
		parseConfigFile(root, classPath);
		return this;
	}
	
	public XlsConfiguration addConfig(File xmlFile) {
		parseConfigFile(root, xmlFile);
		return this;
	}
	
	public XlsConfiguration addConfig(InputStream fin) {
		try {
			parseConfigFile(root, fin);
		} catch (DocumentException e) {
			logger.error("读取配置文件出错！", e);
		}
		return this;
	}
	
	public XlsRoot getRoot() {
		return root;
	}
	
	public XlsEntity getEntity(String className) {
		return root.getEntity(className);
	}
	
	protected void initDefaultConfig(String classPath) {
		InputStream fin = PoiClassLoaderHelper.getResourceAsStream(classPath, this.getClass());
		if (fin == null) {
			return ;
		}
		
		try {
			addConfig(fin);
		} finally {
			if (fin != null) {
				try {
					fin.close();
				} catch (IOException e) {
					logger.error("关闭配置文件出错！", e);
				}
			}
		}
	}
	
	public abstract void flushConfig();
	
	public static void parseConfigFile(XlsRoot cfgRoot, String classPath) {
		InputStream fin = PoiClassLoaderHelper.getResourceAsStream(classPath, XlsConfiguration.class);
		if (fin == null) {
			return ;
		}
		
		try {
			parseConfigFile(cfgRoot, fin);
		} catch (DocumentException e) {
			logger.error("读取配置文件出错！", e);
		} finally {
			if (fin != null) {
				try {
					fin.close();
				} catch (IOException e) {
					logger.error("关闭配置文件出错！", e);
				}
			}
		}
	}
	
	public static void parseConfigFile(XlsRoot cfgRoot, File xmlFile) {
		FileInputStream fin = null;
		try {
			fin = new FileInputStream(xmlFile);
			parseConfigFile(cfgRoot, fin);
		} catch (FileNotFoundException e) {
			logger.error("找不到配置文件！", e);
		} catch (DocumentException e) {
			logger.error("读取配置文件出错！", e);
		} finally {
			if (fin != null) {
				try {
					fin.close();
				} catch (IOException e) {
					logger.error("关闭配置文件出错！", e);
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public static void parseConfigFile(XlsRoot cfgRoot, InputStream fin) throws DocumentException {
		XlsEntity xlsEntity = null;
		Document document = null;
		SAXReader reader = new SAXReader();
		document = reader.read(fin);
		Element eleRoot = document.getRootElement();
		if (eleRoot == null) {
			return;
		}
		if (cfgRoot instanceof XlsImports && !XlsImports.ELE_ROOT.equals(eleRoot.getName())) {
			throw new RuntimeException("Excel导入配置文件格式错误！");
		}
		if (cfgRoot instanceof XlsExports && !XlsExports.ELE_ROOT.equals(eleRoot.getName())) {
			throw new RuntimeException("Excel导出配置文件格式错误！");
		}
		
		// 解析实体配置
		Iterator<Element> iter = eleRoot.elements(XlsEntity.ELE_ENTITY).iterator();
		if (iter != null) {
			while (iter.hasNext()) {
				Element eleEntity = iter.next();
				String className = eleEntity.attributeValue(XlsEntity.PRO_CLASSNAME);
				if (className == null) {
					throw new RuntimeException("className属性不能为空！");
				}
				String fileName = PoiStringHelper.convertNull(eleEntity.attributeValue(XlsEntity.PRO_FILENAME));
				xlsEntity = new XlsEntity(cfgRoot, className, fileName);
				cfgRoot.addEntity(xlsEntity);
				
				// 解析字段配置
				List<Element> fieldElements = eleEntity.elements(XlsProperty.ELE_PROPERTY);
				if (fieldElements != null && fieldElements.size() > 0) {
					XlsProperty property = null;
					for (Element elePro : fieldElements) {
						String name = PoiStringHelper.convertNull(elePro.attributeValue(XlsProperty.PRO_NAME));
						String title = PoiStringHelper.convertNull(elePro.attributeValue(XlsProperty.PRO_TITLE));
						property = new XlsProperty(xlsEntity, name, title);
						if (elePro.attributeValue(XlsProperty.PRO_ENABLE) != null) {
							String enable = elePro.attributeValue(XlsProperty.PRO_ENABLE);
							property.setEnable(Boolean.parseBoolean(enable));
						}
						if (elePro.attributeValue(XlsProperty.PRO_PATTERN) != null) {
							String pattern = elePro.attributeValue(XlsProperty.PRO_PATTERN);
							property.setPattern(pattern);
						}
						if (elePro.attributeValue(XlsProperty.PRO_VALID) != null) {
							String valid = elePro.attributeValue(XlsProperty.PRO_VALID);
							property.setValid(Boolean.parseBoolean(valid));
						}
						if (elePro.attributeValue(XlsProperty.PRO_SEARCH) != null) {
							String search = elePro.attributeValue(XlsProperty.PRO_SEARCH);
							property.setSearch(search);
						}
						xlsEntity.addProperty(property);
					}
				}
			}
		}
	}
}
